<!doctype html><html lang=zh-hans>
<head>
<meta charset=utf-8>
<meta name=viewport content="width=device-width,initial-scale=1">
<meta http-equiv=x-ua-compatible content="IE=edge">
<meta name=author content="小李刀刀">
<meta name=description content="在 MVC 架构的 WEB 应用中，控制器或路由端点需要根据当前活动的 PSR-7 请求来执行相应的业务逻辑代码。本章节就向大家介绍在 Spiral Web 应用中的请求和响应操作。 中间件和原生 PSR-15 处理器会直接接收到代表当前请求的 PSR-7 对象。 请求作用域 读取用户请求的最快捷的方式是通过方法注入直接获得实现 Psr\Http\Message\ServerRequestInterface 接口的实例： namespace App\Controller; use Psr\Http\Message\ServerRequestInterface; use Spiral\Core\Container\SingletonInterface; class HomeController">
<meta name=theme-color content="#3f51b5">
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/academicons/1.8.6/css/academicons.min.css integrity="sha256-uFVgMKfistnJAfoCUQigIl+JfUaP47GrRKjf6CTPVmw=" crossorigin=anonymous>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.0-1/css/all.min.css integrity="sha256-4w9DunooKSr3MFXHXWyFER38WmPdm361bQS/2KUWZbU=" crossorigin=anonymous>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css integrity="sha256-Vzbj7sDDS/woiFS3uNKo8eIuni59rjyNGtXfstRzStA=" crossorigin=anonymous>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/tomorrow-night.min.css crossorigin=anonymous title=hl-light>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/tomorrow-night.min.css crossorigin=anonymous title=hl-dark disabled>
<script src=https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js integrity="sha256-Md1qLToewPeKjfAHU1zyPwOutccPAm5tahnaw7Osw0A=" crossorigin=anonymous async></script>
<link rel=stylesheet href="https://fonts.font.im/css?family=Source+Code+Pro:300,400,500,600,700&subset=latin-ext&display=swap">
<link rel=stylesheet href=/css/academic.css>
<script>(function(b,d,e,a,g){b[a]=b[a]||[],b[a].push({'gtm.start':(new Date).getTime(),event:'gtm.js'});var f=d.getElementsByTagName(e)[0],c=d.createElement(e),h=a!='dataLayer'?'&l='+a:'';c.async=!0,c.src='https://www.googletagmanager.com/gtm.js?id='+g+h,f.parentNode.insertBefore(c,f)})(window,document,'script','dataLayer','GTM-5KZH8N7')</script>
<link rel=manifest href=/index.webmanifest>
<link rel=icon type=image/png href=/images/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_32x32_fill_lanczos_center_3.png>
<link rel=apple-touch-icon type=image/png href=/images/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_192x192_fill_lanczos_center_3.png>
<link rel=canonical href=https://studyspiral.cn/docs/http/request-response/>
<meta property="twitter:card" content="summary">
<meta property="og:site_name" content="Spiral中文网">
<meta property="og:url" content="https://studyspiral.cn/docs/http/request-response/">
<meta property="og:title" content="请求和响应 | Spiral中文网">
<meta property="og:description" content="在 MVC 架构的 WEB 应用中，控制器或路由端点需要根据当前活动的 PSR-7 请求来执行相应的业务逻辑代码。本章节就向大家介绍在 Spiral Web 应用中的请求和响应操作。 中间件和原生 PSR-15 处理器会直接接收到代表当前请求的 PSR-7 对象。 请求作用域 读取用户请求的最快捷的方式是通过方法注入直接获得实现 Psr\Http\Message\ServerRequestInterface 接口的实例： namespace App\Controller; use Psr\Http\Message\ServerRequestInterface; use Spiral\Core\Container\SingletonInterface; class HomeController"><meta property="og:image" content="https://studyspiral.cn/images/logo.svg">
<meta property="twitter:image" content="https://studyspiral.cn/images/logo.svg"><meta property="og:locale" content="zh-Hans">
<meta property="article:published_time" content="2020-04-12T23:21:35+08:00">
<meta property="article:modified_time" content="2020-04-19T23:56:47+08:00">
<script src=https://cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.1/cookieconsent.min.js integrity="sha256-5VhCqFam2Cn+yjw61zbBNrbHVJ6SRydPeKopYlngbiQ=" crossorigin=anonymous></script>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.1/cookieconsent.min.css integrity="sha256-zQ0LblD/Af8vOppw18+2anxsuaz3pWYyVWi+bTvTH8Q=" crossorigin=anonymous>
<script>window.addEventListener("load",function(){window.cookieconsent.initialise({palette:{popup:{background:"#3f51b5",text:"#fff"},button:{background:"#fff",text:"#3f51b5"}},theme:"classic",content:{message:"本网站使用cookies来确保您在本网站上获得最佳体验。",dismiss:"知道了!",link:"了解更多",href:"https://www.cookiesandyou.com"}})})</script>
<title>请求和响应 | Spiral中文网</title>
</head>
<body id=top data-spy=scroll data-offset=70 data-target=#TableOfContents>
<aside class=search-results id=search>
<div class=container>
<section class=search-header>
<div class="row no-gutters justify-content-between mb-3">
<div class=col-6>
<h1>搜索</h1>
</div>
<div class="col-6 col-search-close">
<a class=js-search href=#><i class="fas fa-times-circle text-muted" aria-hidden=true></i></a>
</div>
</div>
<div id=search-box>
<input name=q id=search-query placeholder=搜索... autocapitalize=off autocomplete=off autocorrect=off spellcheck=false type=search>
</div>
</section>
<section class=section-search-results>
<div id=search-hits>
</div>
</section>
</div>
</aside>
<nav class="navbar navbar-expand-lg navbar-light compensate-for-scrollbar" id=navbar-main>
<div class=container>
<div class="d-none d-lg-inline-flex">
<a class=navbar-brand href=/><img src=/images/logo.svg alt=Spiral中文网>Spiral中文网</a>
</div>
<button type=button class=navbar-toggler data-toggle=collapse data-target=#navbar-content aria-controls=navbar aria-expanded=false aria-label=切换导航>
<span><i class="fas fa-bars"></i></span>
</button>
<div class="navbar-brand-mobile-wrapper d-inline-flex d-lg-none">
<a class=navbar-brand href=/><img src=/images/logo.svg alt=Spiral中文网>Spiral中文网</a>
</div>
<div class="navbar-collapse main-menu-item collapse justify-content-end" id=navbar-content>
<ul class="navbar-nav d-md-inline-flex">
<li class=nav-item>
<a class=nav-link href=/docs/basics/quick-start/><span>教程</span></a>
</li>
<li class=nav-item>
<a class="nav-link active" href=/docs/><span>文档</span></a>
</li>
<li class=nav-item>
<a class=nav-link href=/post/><span>文章</span></a>
</li>
</ul>
</div>
<ul class="nav-icons navbar-nav flex-row ml-auto d-flex pl-md-2">
<li class=nav-item>
<a class="nav-link js-search" href=#><i class="fas fa-search" aria-hidden=true></i></a>
</li>
</ul>
</div>
</nav>
<div class="container-fluid docs">
<div class="row flex-xl-nowrap">
<div class="col-12 col-md-3 col-xl-2 docs-sidebar">
<form class="docs-search d-flex align-items-center">
<button class="btn docs-toggle d-md-none p-0 mr-3" type=button data-toggle=collapse data-target=#docs-nav aria-controls=docs-nav aria-expanded=false aria-label="Toggle section navigation">
<span><i class="fas fa-bars"></i></span>
</button>
<input name=q type=search class=form-control placeholder=搜索... autocomplete=off>
</form>
<nav class="collapse docs-links" id=docs-nav>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/extension/dotenv/>Dotenv</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/>总览</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse show">
<li>
<a href=/docs/>Spiral介绍</a>
</li>
<li>
<a href=/docs/about/contributing/>贡献指引</a>
</li>
<li>
<a href=/docs/about/semver/>版本说明</a>
</li>
<li>
<a href=/docs/about/license/>授权协议</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/http/psr-15/>定制 PSR-15 处理器</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/start/install/>快速开始</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/start/install/>安装指引</a>
</li>
<li>
<a href=/docs/start/workers/>应用工作进程</a>
</li>
<li>
<a href=/docs/start/structure/>应用程序结构</a>
</li>
<li>
<a href=/docs/start/configuration/>默认配置</a>
</li>
<li>
<a href=/docs/start/commands/>控制台命令</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/basics/quick-start/>入门基础</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/basics/quick-start/>上手指南</a>
</li>
<li>
<a href=/docs/basics/scaffolding/>脚手架</a>
</li>
<li>
<a href=/docs/basics/prototype/>原型开发辅助</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/framework/design/>核心框架</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/framework/design/>设计理念</a>
</li>
<li>
<a href=/docs/framework/application-server/>应用服务器</a>
</li>
<li>
<a href=/docs/framework/config/>配置对象</a>
</li>
<li>
<a href=/docs/framework/kernel/>内核与环境</a>
</li>
<li>
<a href=/docs/framework/container/>容器</a>
</li>
<li>
<a href=/docs/framework/bootloaders/>引导程序</a>
</li>
<li>
<a href=/docs/framework/scopes/>IoC 作用域</a>
</li>
<li>
<a href=/docs/framework/memory/>静态高速缓存</a>
</li>
<li>
<a href=/docs/framework/finalizers/>终结器</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/cookbook/annotated-routes/>速查手册</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/cookbook/annotated-routes/>注解式路由</a>
</li>
<li>
<a href=/docs/cookbook/injector/>容器注入器</a>
</li>
<li>
<a href=/docs/cookbook/domain-core/>领域内核、控制器</a>
</li>
<li>
<a href=/docs/cookbook/golang-library/>Golang服务集成</a>
</li>
<li>
<a href=/docs/cookbook/custom-dispatcher/>自定义调度器</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/component/files/>常用组件</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/component/files/>文件和目录</a>
</li>
<li>
<a href=/docs/component/reactor/>代码生成</a>
</li>
<li>
<a href=/docs/component/tokenizer/>静态分析工具</a>
</li>
<li>
<a href=/docs/component/metrics/>应用指标</a>
</li>
<li>
<a href=/docs/component/data-grid/>数据网格</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/console/configuration/>控制台</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/console/configuration/>安装和配置</a>
</li>
<li>
<a href=/docs/console/commands/>用户命令</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/http/configuration/>HTTP</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse show">
<li>
<a href=/docs/http/configuration/>安装配置</a>
</li>
<li>
<a href=/docs/http/lifecycle/>请求生命周期</a>
</li>
<li class=active>
<a href=/docs/http/request-response/>请求和响应</a>
</li>
<li>
<a href=/docs/http/routing/>路由</a>
</li>
<li>
<a href=/docs/http/errors/>错误页面</a>
</li>
<li>
<a href=/docs/http/middleware/>中间件</a>
</li>
<li>
<a href=/docs/http/golang/>Golang 中间件</a>
</li>
<li>
<a href=/docs/http/cookies/>Cookies</a>
</li>
<li>
<a href=/docs/http/session/>Session</a>
</li>
<li>
<a href=/docs/http/csrf/>CSRF 防护</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/security/encrypter/>安全</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/security/encrypter/>数据加密</a>
</li>
<li>
<a href=/docs/security/validation/>数据验证</a>
</li>
<li>
<a href=/docs/security/rbac/>基于角色的权限控制</a>
</li>
<li>
<a href=/docs/security/authentication/>用户认证</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/filters/configuration/>请求过滤</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/filters/configuration/>安装和配置</a>
</li>
<li>
<a href=/docs/filters/filter/>过滤器</a>
</li>
<li>
<a href=/docs/filters/composite/>复合过滤器</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/database/configuration/>数据库</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/database/configuration/>安装与配置</a>
</li>
<li>
<a href=/docs/database/access/>访问数据</a>
</li>
<li>
<a href=/docs/database/isolation/>逻辑隔离</a>
</li>
<li>
<a href=/docs/database/query-builders/>查询构造器</a>
</li>
<li>
<a href=/docs/database/transactions/>Transactions</a>
</li>
<li>
<a href=/docs/database/introspection/>Schema Introspection</a>
</li>
<li>
<a href=/docs/database/declaration/>Declaration</a>
</li>
<li>
<a href=/docs/database/migrations/>Migrations</a>
</li>
<li>
<a href=/docs/database/errata/>Errata</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/cycle/configuration/>Cycle ORM</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/cycle/configuration/>Configuration</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/queue/configuration/>队列任务</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/queue/configuration/>Configuration</a>
</li>
<li>
<a href=/docs/queue/scraper/>网站爬虫</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/views/configuration/>视图</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/views/configuration/>Configuration</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/stempler/configuration/>Stempler 模板</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/stempler/configuration/>Configuration</a>
</li>
<li>
<a href=/docs/stempler/directives/>Directives</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>国际化</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>GRPC</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>事件广播</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>调试及性能</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>扩展</a>
</div>
</nav>
</div>
<div class="d-none d-xl-block col-xl-2 docs-toc">
<ul class="nav toc-top">
<li><a href=# id=back_to_top class=docs-toc-title>在本页</a></li>
</ul>
<nav id=TableOfContents>
<ul>
<li><a href=#请求作用域>请求作用域</a></li>
<li><a href=#请求上下文管理器inputmanager>请求上下文管理器（InputManager）</a>
<ul>
<li><a href=#请求头信息>请求头信息</a></li>
<li><a href=#cookies>Cookies</a></li>
<li><a href=#服务器变量>服务器变量</a></li>
<li><a href=#postdata-请求数据>Post/Data 请求数据</a></li>
<li><a href=#postdata-数据兼容查询字符串>Post/Data 数据兼容查询字符串</a></li>
<li><a href=#psr7-请求属性>PSR7 请求属性</a></li>
<li><a href=#上传文件>上传文件</a></li>
<li><a href=#简化方法>简化方法</a></li>
</ul>
</li>
<li><a href=#inputinterface>InputInterface</a></li>
<li><a href=#生成响应>生成响应</a></li>
<li><a href=#json-响应>JSON 响应</a></li>
<li><a href=#响应工厂>响应工厂</a></li>
<li><a href=#响应包装类>响应包装类</a></li>
</ul>
</nav>
</div>
<main class="col-12 col-md-9 col-xl-8 py-md-3 pl-md-5 docs-content" role=main>
<article class=article>
<div class="alert alert-warning" role=alert>
官方文档中文版翻译工作仍在进行中，欢迎 <a href=/post/join-translation/>参与翻译</a>。
</div>
<div class=docs-article-container>
<h1>请求和响应</h1>
<div class=article-style>
<p>在 MVC 架构的 WEB 应用中，控制器或路由端点需要根据当前活动的 PSR-7 请求来执行相应的业务逻辑代码。本章节就向大家介绍在 Spiral Web 应用中的请求和响应操作。</p>
<blockquote>
<p>中间件和原生 PSR-15 处理器会直接接收到代表当前请求的 PSR-7 对象。</p>
</blockquote>
<h2 id=请求作用域>请求作用域</h2>
<p>读取用户请求的最快捷的方式是通过方法注入直接获得实现 <code>Psr\Http\Message\ServerRequestInterface</code> 接口的实例：</p>
<pre><code class=language-php>namespace App\Controller;

use Psr\Http\Message\ServerRequestInterface;
use Spiral\Core\Container\SingletonInterface;

class HomeController implements SingletonInterface
{
    public function index(ServerRequestInterface $request)
    {
        dump($request-&gt;getHeaders());
    }
}
</code></pre>
<blockquote>
<p>注意：不允许在单例对象的构造函数中注入 <code>ServerRequestInterface</code>，存在用户信息泄露的危险。</p>
</blockquote>
<p>获得请求对象后，你就可以调用
<a href=https://www.php-fig.org/psr/psr-7/ target=_blank rel=noopener>PSR-7 标准</a> 定义的所有读取方法了。</p>
<h2 id=请求上下文管理器inputmanager>请求上下文管理器（InputManager）</h2>
<p>除了 PSR-7 请求对象外，你也可以使用 Spiral 提供的请求上下文管理器 <code>Spiral\Http\Request\InputManager</code>，这是可以存储在单例服务、控制器中的对象，而且通过它访问到的始终是当前活动的用户请求。除此之外，它比 PSR-7 请求对象还提供了更多方便快捷的方法来读取传入数据。</p>
<pre><code class=language-php>namespace App\Controller;

use Spiral\Core\Container\SingletonInterface;
use Spiral\Http\Request\InputManager;

class HomeController implements SingletonInterface
{
    private $input;

    public function __construct(InputManager $input)
    {
        $this-&gt;input = $input;
    }

    public function index()
    {
        dump($this-&gt;input-&gt;query-&gt;all());
    }
}
</code></pre>
<p>如果使用了 <code>原型开发辅助（PrototypeTrait）</code>，不需要方法注入就可以快捷地调用 <code>InputManager</code>，通过 <code>$this->request</code>：</p>
<pre><code class=language-php>namespace App\Controller;

use Spiral\Prototype\Traits\PrototypeTrait;

class HomeController
{
    use PrototypeTrait;

    public function index()
    {
        // $this-&gt;request 是 $this-&gt;input 的别名
        dump($this-&gt;request-&gt;data-&gt;all());
    }
}
</code></pre>
<blockquote>
<p>请注意，除非有必要，否则不建议直接访问 <code>ServerRequestInterface</code> 或者 <code>InputManager</code>，最好使用 <code>请求过滤（Request Filter）</code> 来过滤和获取用户传入数据。</p>
</blockquote>
<p>通过 <code>InputManager</code> 辅助对象可以访问输入数据中的所有数组（Query, Cookie, Header, Post Data 等），或者其它特定的字段（对于对象中的嵌套数组和对象，可以用点表示法（dot notation）访问深层次的字段）。每个输入结构都用带有一组常用方法的 <code>InputBag</code> 类表示，以查询参数为例：</p>
<pre><code class=language-php>/**
 * @var InputManager $input
 */

// 获得 QueryBag 实例，对应 URL 查询参数传递的数据
dump($input-&gt;query);

// 获得查询参数数组
dump($input-&gt;query-&gt;all());

// 获得查询参数个数
dump($input-&gt;query-&gt;count());

// 检查名为 &quot;name&quot; 的查询参数是否存在
dump($input-&gt;query-&gt;has('name'));

// 获得名为 &quot;name&quot; 的查询参数
dump($input-&gt;query-&gt;get('name'));

// get 和 has 方法都支持用点表示法获得嵌套结构中的数据
dump($input-&gt;query-&gt;has('name.subName'));
dump($input-&gt;query-&gt;get('name.subName'));

// 只返回指定名称的查询参数（不允许点表示法），只有指定的且存在的参数会返回
dump($input-&gt;query-&gt;fetch([&quot;name&quot;, &quot;nameB&quot;]);

// 只返回指定名称的查询参数（不允许点表示法），不存在的参数同样返回，但值被设置为 `null`
dump($input-&gt;query-&gt;fetch(['name', 'nameB'], true, null);

// 查询参数的 get 方法可以用简短的别名方式调用，更加简洁
dump($input-&gt;query('name'));
</code></pre>
<h3 id=请求头信息>请求头信息</h3>
<p>如果要读取请求头信息，可以用 <code>InputManager</code> 的 <code>header</code> 方法，返回的是 <code>HeadersBag</code>，它也包含了一些有用的方法：</p>
<ul>
<li>HeaderBag 会自动规范头信息名称，因此开发者可以不用关注大小写的问题</li>
<li>&ldquo;get&rdquo; 方法默认会自动把包含 &ldquo;,&rdquo; 的头信息值用 implode 方法进行拆分</li>
</ul>
<pre><code class=language-php>// 所有请求头信息
dump($input-&gt;headers-&gt;all());

// &quot;accept&quot; 会自动规范成 &quot;Accept&quot;
dump($input-&gt;headers-&gt;get('accept'));

// 返回的 Accept 头信息会转为数组（浏览器大部分时候会附带多个 accept 值）
dump($input-&gt;headers-&gt;get('accept', false));

// HeaderBag 的 &quot;get&quot; 方法也有别名
dump($input-&gt;header('accept'));
</code></pre>
<h3 id=cookies>Cookies</h3>
<pre><code class=language-php>// 包含所有 cookie 信息的数组
dump($input-&gt;cookies-&gt;all());
dump($input-&gt;cookie('name'));
</code></pre>
<h3 id=服务器变量>服务器变量</h3>
<pre><code class=language-php>dump($input-&gt;server-&gt;all());
dump($input-&gt;server('name'));
</code></pre>
<blockquote>
<p>注意：ServerBag 会自动规范化请求中包含的所有服务器变量，因此在调用相关的变量值时传入的键名不必区分大小写。</p>
</blockquote>
<pre><code class=language-php>dump($input-&gt;server('SERVER_PORT'));
dump($input-&gt;server('server-port'));
</code></pre>
<h3 id=postdata-请求数据>Post/Data 请求数据</h3>
<pre><code class=language-php>dump($input-&gt;data-&gt;all());
dump($input-&gt;data('name'));

// 别名
dump($input-&gt;post('name'));
</code></pre>
<h3 id=postdata-数据兼容查询字符串>Post/Data 数据兼容查询字符串</h3>
<p>有时候，我们会希望在 Post 数据中找不到需要的数据时，自动从查询字符串（Query）中查询，这种情况下，只要使用 <code>input</code> 方法就可以：</p>
<pre><code class=language-php>dump($input-&gt;input('name'));
</code></pre>
<h3 id=psr7-请求属性>PSR7 请求属性</h3>
<pre><code class=language-php>dump($input-&gt;attributes-&gt;all());
dump($input-&gt;attribute('name'));
</code></pre>
<h3 id=上传文件>上传文件</h3>
<p>要获取上传的所有文件，或者单个文件，可以通过 <code>files</code> 包以及 <code>file</code> 方法。每一个成功上传的文件都表示为实现 <code>UploadFileInterface</code> 接口的实例，它其实是 PSR7 标准的一部分：</p>
<pre><code class=language-php>dump($this-&gt;input-&gt;files-&gt;all());
dump($this-&gt;input-&gt;file('upload'));
</code></pre>
<blockquote>
<p>根据 PSR 规范，所有文件都按照逻辑层次结构进行组织，这与 PHP 处理上传文件的默认方式有所不同。你可以使用点表示法来访问嵌套的文件实例。</p>
</blockquote>
<h3 id=简化方法>简化方法</h3>
<p>在 data 方法和 InputBags 之外，<code>InputManager</code> 提供了大量用于读取当前请求的各种属性的简化方法：</p>
<pre><code class=language-php>// 请求的 Uri 中的路径，总是包含开头的 &quot;/&quot;
dump($input-&gt;path());

// 当前请求的 Uri
dump($input-&gt;uri());

// 当前请求的方法（动词），GET, POST, PUT 等
dump($input-&gt;method());

// 判断当前请求是否采用 https
dump($input-&gt;isSecure());

// 通过请求头信息判断这是否 Ajax 请求
dump($input-&gt;isAjax());

// 判断当前请求是否希望获得 `application/json` 类型的响应（Accept: application/json）
dump($input-&gt;isJsonExpected());

// 获取客户 ip 地址（这个方法使用 _SERVER 里的值，有时候得到并不是正确的用户 ip）
dump($input-&gt;remoteAddress());
</code></pre>
<p>不通过 <code>__get</code> 魔术方法获取 <code>InputBag</code>，可以这样做：</p>
<pre><code class=language-php>dump($input-&gt;bag('data')-&gt;all());
</code></pre>
<h2 id=inputinterface>InputInterface</h2>
<p><code>InputManager</code> 这个辅助类中的方法没有 <code>get</code> 前缀。原因是在外部组件 <code>spiral/filters</code> 中，需要通过 <code>Spiral\Filters\InputInterface</code> 来提供数据源。</p>
<pre><code class=language-php>namespace Spiral\Filters;

// ...

interface InputInterface
{
    public function withPrefix(string $prefix, bool $add = true): InputInterface;

    public function getValue(string $source, string $name = null);
}
</code></pre>
<p>你可以通过 <code>InputInterface</code> 的短符号来调用 <code>InputManager</code> 的方法。两种方式返回的数据是相同的。</p>
<pre><code class=language-php>public function index(InputInterface $inputSource, InputManager $inputManager)
{
    dump($inputManager-&gt;query('name'));
    dump($inputSource-&gt;getValue('query', 'name'));

    dump($inputManager-&gt;path());
    dump($inputSource-&gt;getValue('path'));
}
</code></pre>
<p>这一实现主要用于把输入数据映射到请求过滤器（Request Filter）。</p>
<blockquote>
<p>如果要访问 <code>Spiral\Filter\InputInterface</code>，必须激活 <code>Spiral\Bootloader\Security\FiltersBootloader</code> 引导程序。</p>
</blockquote>
<h2 id=生成响应>生成响应</h2>
<p>在控制器方法中可以返回任何实现 <code>Psr\Http\Message\ResponseInterface</code> 接口的实例，它们会被直接发送给用户。</p>
<pre><code class=language-php>namespace App\Controller;

use Nyholm\Psr7\Response;
use Psr\Http\Message\ResponseInterface;

class HomeController
{
    public function index(): ResponseInterface
    {
        $r = new Response(200);
        $r-&gt;getBody()-&gt;write(&quot;hello world&quot;);

        return $r;
    }
}
</code></pre>
<p>Spiral 默认启用的 PSR-15 处理器提供了基于返回字符串或输出缓冲区的内容自动生成响应对象的能力：</p>
<pre><code class=language-php>namespace App\Controller;

class HomeController
{
    public function index(): string
    {
        return &quot;hello world&quot;;
    }
}
</code></pre>
<p>下面的示例可以达到与上面相同的结果：</p>
<pre><code class=language-php>namespace App\Controller;

class HomeController
{
    public function index()
    {
        echo &quot;hello world&quot;;
    }
}
</code></pre>
<blockquote>
<p>为了采用严格的返回数据类型，建议只在开发阶段为了显示 debug 信息才使用输出缓冲区。</p>
</blockquote>
<h2 id=json-响应>JSON 响应</h2>
<p>除了字符串，默认的 PSR-15 处理器还支持数组和 <code>JsonSerializable</code> 响应，并自动将它们转换为 JSON:</p>
<pre><code class=language-php>namespace App\Controller;

class HomeController
{
    public function index(): array
    {
        return [
            'status' =&gt; 200,
            'data'   =&gt; ['some' =&gt; 'json']
        ];
    }
}
</code></pre>
<h2 id=响应工厂>响应工厂</h2>
<p>对手动创建响应进行抽象的正确方式是使用 <code>Psr\Http\Message\ResponseFactoryInterface</code>:</p>
<pre><code class=language-php>namespace App\Controller;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;

class HomeController
{
    public function index(ResponseFactoryInterface $responseFactory): ResponseInterface
    {
        $response = $responseFactory-&gt;createResponse(200);
        $response-&gt;getBody()-&gt;write(&quot;hello world&quot;);

        return $response;
    }
}
</code></pre>
<h2 id=响应包装类>响应包装类</h2>
<p>为了生成更复杂的响应，可以使用 Spiral 提供的响应包装类 <code>Spiral\Http\ResponswWrapper</code>，它对 <code>ResponseFactoryInterface</code> 进行了实现和包装，增加了一些方法，用于简化响应的处理：</p>
<pre><code class=language-php>namespace App\Controller;

use Psr\Http\Message\ResponseInterface;
use Spiral\Http\ResponseWrapper;

class HomeController
{
    public function index(ResponseWrapper $r): ResponseInterface
    {
        return $r-&gt;attachment(
            __FILE__,
            'controller.php'
        )-&gt;withAddedHeader('Key', 'value');
    }
}
</code></pre>
<p>通过原型开发辅助 <code>PrototypeTrait</code> 的 <code>response</code> 属性，可以快速访问响应包装类：</p>
<pre><code class=language-php>namespace App\Controller;

use Psr\Http\Message\ResponseInterface;
use Spiral\Prototype\Traits\PrototypeTrait;

class HomeController
{
    Use PrototypeTrait;

    public function index(): ResponseInterface
    {
        // 临时重定向
        return $this-&gt;response-&gt;redirect('https://google.com', 307);
    }
}
</code></pre>
<p>创建 HTML 格式的响应：</p>
<pre><code class=language-php>public function index()
{
    return $this-&gt;response-&gt;html('hello world');
}
</code></pre>
<p>创建 JSON 响应：</p>
<pre><code class=language-php>public function index()
{
    return $this-&gt;response-&gt;json(
        ['something' =&gt; 123],
        200
    );
}
</code></pre>
<p>发送附件：</p>
<pre><code class=language-php>public function index()
{
    return $this-&gt;response-&gt;attachment(__FILE__, 'name.php');
}
</code></pre>
<blockquote>
<p>提示：你也可以用 StreamInterface 的实现作为第一个参数，并在第三个参数指定要使用的 mime-type.</p>
</blockquote>
</div>
<div class=article-widget>
<div class=post-nav>
<div class=post-nav-item>
<div class=meta-nav>上一页</div>
<a href=/docs/cycle/configuration/ rel=next>Configuration</a>
</div>
<div class=post-nav-item>
<div class=meta-nav>下一页</div>
<a href=/docs/http/routing/ rel=prev>路由</a>
</div>
</div>
</div>
</div>
<div class=body-footer>
<p>最近更新于 2020-04-19</p>
<p class=edit-page>
<a href=https://github.com/krwu/spiraldocs/edit/feat/chinese/zh_CN/http/request-response.md>
<i class="fas fa-pen pr-2"></i>编辑本页
</a>
</p>
</div>
</article>
<footer class=site-footer>
<p class=powered-by><span class=copyright>© 2019 - 2021 <a href=https://studyspiral.cn/>StudySpiral</a> All rights reserved.</span>
</p>
<p class=powered-by>
<a href=http://www.beian.miit.gov.cn/ target=_blank rel="noopener noreferer">粤ICP备14011364号</a>
<a href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=44030402001866" target=_blank rel="noopener noreferer"><img style=display:inline-block src=/img/gaba.png>粤公网安备 44030402001866号</a>
</p>
<p id=webify class=powered-by style=display:flex><span style="margin:0 .2rem 0 0;display:block;height:20px;line-height:20px">Powered by</span> <a href=https://webify.cloudbase.net/ target=_blank rel=noopener>CloudBase Webify</a></p>
<script async defer>window.addEventListener('DOMContentLoaded',()=>{const{host:a}=window.location;(a.toLocaleLowerCase()==='docs.studyspiral.cn'||a.indexOf(".app.tcloudbase.com"))&&(document.getElementById('webify').style.display='flex')})</script>
</footer>
</main>
</div>
</div>
<script src=https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/4.1.4/imagesloaded.pkgd.min.js integrity="sha256-lqvxZrPLtfffUl2G/e7szqSvPBILGbwmsGE1MKlOi0Q=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/jquery.isotope/3.0.6/isotope.pkgd.min.js integrity="sha256-CBrpuqrMhXwcLLUd5tvQ4euBHCdh7wGlDfNz8vbu/iI=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js integrity="sha256-yt2kYMy0w8AbtF89WXb2P1rfjcP/HTHLT7097U8Y5b8=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js integrity="sha256-eOgo0OtLL4cdq7RdwRUiGKLX9XsIJ7nGhWEKbohmVAQ=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/languages/go.min.js></script>
<script>const code_highlighting=!0</script>
<script>const isSiteThemeDark=!1</script>
<script>const search_config={indexURI:"/index.json",minLength:1,threshold:.3},i18n={no_results:"没有找到结果",placeholder:"搜索...",results:"搜索结果"},content_type={post:"文章",project:"项目",publication:"出版物",talk:"演讲"}</script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4.1.1/anchor.min.js integrity="sha256-pB/deHc9CGfFpJRjC43imB29Rse8tak+5eXqntO94ck=" crossorigin=anonymous></script>
<script>anchors.add()</script>
<script id=search-hit-fuse-template type=text/x-template>
      <div class="search-hit" id="summary-{{key}}">
      <div class="search-hit-content">
        <div class="search-hit-name">
          <a href="{{relpermalink}}">{{title}}</a>
          <div class="article-metadata search-hit-type">{{type}}</div>
          <p class="search-hit-description">{{snippet}}</p>
        </div>
      </div>
      </div>
    </script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.2.1/fuse.min.js integrity="sha256-VzgmKYmhsGNNN4Ph1kMW+BjoYJM2jV5i4IlFoeZA9XI=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/jquery.mark.min.js integrity="sha256-4HLtjeVgH0eIB3aZ9mLYF6E8oU5chNdjU6p6rrXpl9U=" crossorigin=anonymous></script>
<script src=/js/academic.min.6f1005d1a84220e2f466ff3d8e712f31.js></script>
<div id=modal class="modal fade" role=dialog>
<div class=modal-dialog>
<div class=modal-content>
<div class=modal-header>
<h5 class=modal-title>引用</h5>
<button type=button class=close data-dismiss=modal aria-label=Close>
<span aria-hidden=true>&#215;</span>
</button>
</div>
<div class=modal-body>
<pre><code class="tex hljs"></code></pre>
</div>
<div class=modal-footer>
<a class="btn btn-outline-primary my-1 js-copy-cite" href=# target=_blank>
<i class="fas fa-copy"></i> 复制
</a>
<a class="btn btn-outline-primary my-1 js-download-cite" href=# target=_blank>
<i class="fas fa-download"></i> 下载
</a>
<div id=modal-error></div>
</div>
</div>
</div>
</div>
</body>
</html>